/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_ttc8_tti_oac.c                                 */
/*  NOTE      =                                                    */
/*  DATE      = 2014/10/23 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>

#include "frcomm.h"

#include "conntrack.h"

#include "../../ora_core.h"
#include "../../comm/ora_comm.h"
#include "../../comm/ora_stmt.h"
#include "../../comm/ora_util.h"
#include "../ora_mar_engine.h"
#include "ora_ttc8_tti_oac.h"

/*******************************************************************************
*  FUNC     :  分析oac部分
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*           :  i_oac_type                           (APM_ORA_OACTYPE_DEFINE/APM_ORA_OACTYPE_BIND/APM_ORA_OACTYPE_COLUMN)
*           :  *p_st_stmt                           (statement)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc8_tti_oac_analyze(Conntrack *p_st_conn
                            , L7session_ora *p_st_sess
                            , L7_ora_packet *p_st_ora_packet
                            , int i_index)
{
    ORA_PRINT_INFO("enter ora_ttc8_tti_oac_analyze\n");
    short s_tmp = 0;
    int i_tmp = 0;
    long long ll_tmp = 0LL;
    short s_oacdty = 0;
    short s_oacscl = 0;
    int i_oacmxl = 0;
    int i_pos_for_check_oacscl = 0;

    if (p_st_sess->i_use_special_field == FR_YES &&
            i_index == 0 &&
            p_st_sess->i_ttc8_stmt_resp_oac_skip1 == FR_YES &&
            (ora_mar_peekUB1(p_st_ora_packet, &s_tmp) != FR_SUCC || s_tmp == 0x00))
        goto error;

    if (p_st_sess->i_ttc8_stmt_resp_oac_skip1 == FR_YES)
    {
        if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // skip 1 byte
            goto error;
        if (s_tmp != 0x01 && s_tmp != 0x00)
            goto error;
    }

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacdty) != FR_SUCC) // oacdty
        goto error;
    if (ora_util_check_dty(s_oacdty) != FR_SUCC)
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // oacflg
        goto error;
    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // oacpre
        goto error;

    if (p_st_sess->i_use_oci == FR_YES)
    {
        if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // oacscl
            goto error;
    }
    else
    {
        if (s_oacdty == ORA_DTY_NUMBER ||
            s_oacdty == ORA_DTY_TIMESTAMP ||
            s_oacdty == ORA_DTY_TIMESTAMPTZ ||
            s_oacdty == ORA_DTY_TIMESTAMPLTZ ||
            s_oacdty == ORA_DTY_INTERVALDS)
        {
            i_pos_for_check_oacscl = bytebuff_getPosition(p_st_ora_packet->p_st_packet);
            if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC) // oacscl
                goto error;
        }
        else
        {
            if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // oacscl
                goto error;
        }
    }

    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_oacmxl) != FR_SUCC) // oacmxl
    {
        if (i_pos_for_check_oacscl != 0)
        {
            if (bytebuff_setPosition(p_st_ora_packet->p_st_packet, i_pos_for_check_oacscl) != FR_SUCC)
                goto error;
            if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacscl) != FR_SUCC) // oacscl
                goto error;
            if (s_oacscl == 0x81)
            {
                if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_oacmxl) != FR_SUCC) // oacmxl
                    goto error;
                p_st_sess->i_use_oci = FR_YES;
                p_st_sess->i_ptr_len = APM_ORA_PTR_LEN_1;
                ORA_PRINT_FATAL("set p_st_sess->i_use_oci = FR_YES, p_st_sess->i_ptr_len = 1\n");
            }
            else
                goto error;
        }
        else
            goto error;
    }
    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC) // oacmal
        goto error;
    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC) // oacfl2
        goto error;
    if (ora_mar_skipDALC(p_st_sess, p_st_ora_packet) != FR_SUCC) // oactoid
        goto error;
    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC) // oacvsn
        goto error;

    if (p_st_sess->i_ttc8_stmt_resp_oac_skip1 == FR_YES &&
        s_oacdty != ORA_DTY_ANYTYPE && s_oacdty != ORA_DTY_NAMED_TYPE && s_oacdty != ORA_DTY_NAMED_TYPE2)
    {
        if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC || i_tmp != 0) // skip 2 bytes
            goto error;
        if (p_st_sess->i_ttc8_stmt_resp_oac_skipaftervsn == FR_YES)
        {
            if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_tmp) != FR_SUCC || ll_tmp != 0LL) // skip 4 bytes
                goto error;
        }
    }

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC) // oaccsi
        goto error;
    if (i_tmp != 0 && ora_util_check_charset(i_tmp) != FR_SUCC)
        goto error;
    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC) // oaccsfrm
        goto error;

    // 不支持c_ttc_version<2的版本
    // 不支持s_tns_version<312的版本(8i)
    // p_st_sess->i_use_special_field == FR_NO || (p_st_sess->i_use_special_field == FR_YES && p_st_sess->s_tns_version >= 312)
    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC) // oacmxlc
        goto error;

    if (p_st_sess->i_ttc8_stmt_resp_oac_skip1 == FR_YES &&
        s_oacdty != ORA_DTY_ANYTYPE && s_oacdty != ORA_DTY_NAMED_TYPE && s_oacdty != ORA_DTY_NAMED_TYPE2)
    {
        if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_tmp) != FR_SUCC || s_tmp != 0) // skip 1 byte
            goto error;
        if (p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_8)
        {
            if (ora_mar_unmarshalUB4(p_st_sess, p_st_ora_packet, &ll_tmp) != FR_SUCC || ll_tmp != 0LL) // skip 4 bytes
                goto error;
        }
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  对应于 void unmarshal() 方法
*  ARGS     :  *p_st_conn                           (ct信息)
*           :  *p_st_sess                           (Oracle私有的session)
*           :  *p_st_ora_packet                     (Oracle数据包)
*           :  i_oac_type                           (APM_ORA_OACTYPE_DEFINE/APM_ORA_OACTYPE_BIND/APM_ORA_OACTYPE_COLUMN)
*           :  *p_st_stmt                           (statement)
*  RTN      :  0                                    (FR_SUCC)
*              1                                    (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int ora_ttc8_tti_oac_unmarshal(Conntrack *p_st_conn
                            , L7session_ora *p_st_sess
                            , L7_ora_packet *p_st_ora_packet
                            , int i_oac_type
                            , Sql_statement *p_st_stmt)
{
    ORA_PRINT_INFO("enter oac\n");
    int i_tmp = 0;
    Ora_metadata st_ora_metadata;
    memset(&st_ora_metadata, 0x00, sizeof(Ora_metadata));

    short s_oacdty = 0;
    short s_oacflg = 0;
    short s_oacpre = 0;
    short s_oacscl = 0;
    int i_oacmxl = 0;
    int i_oacmal = 0;
    int i_oacfl2 = 0;
    int i_oacvsn = 0;
    int i_oaccsi = 0;
    short s_oaccsfrm = 0;
    int i_oacmxlc = -1;
    int i_pos_for_check_oacscl = 0;

    if (p_st_sess->i_ttc8_stmt_resp_oac_skip1 == FR_YES) // p_st_sess->i_use_special_field == FR_YES && p_st_sess->i_send_typerep == FR_NO
    {
        ORA_PRINT_DBG("oac skip OCI1\n");
        if (ora_mar_skip(p_st_ora_packet, 1) != FR_SUCC)
            goto error;
    }

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacdty) != FR_SUCC) // oacdty
        goto error;
    ORA_PRINT_DTY_INFO((char *) "s_oacdty:[%s]\n", s_oacdty);

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacflg) != FR_SUCC) // oacflg
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacpre) != FR_SUCC) // oacpre
        goto error;

    if (p_st_sess->i_use_oci == FR_YES)
    {
        if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacscl) != FR_SUCC) // oacscl
            goto error;
    }
    else
    {
        if (s_oacdty == ORA_DTY_NUMBER ||
                s_oacdty == ORA_DTY_TIMESTAMP ||
                s_oacdty == ORA_DTY_TIMESTAMPTZ ||
                s_oacdty == ORA_DTY_TIMESTAMPLTZ ||
                s_oacdty == ORA_DTY_INTERVALDS)
        {
            i_pos_for_check_oacscl = bytebuff_getPosition(p_st_ora_packet->p_st_packet);
            if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_tmp) != FR_SUCC) // oacscl
                goto error;
            s_oacscl = (short) i_tmp;
        }
        else
        {
            if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacscl) != FR_SUCC) // oacscl
                goto error;
        }
    }

    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_oacmxl) != FR_SUCC) // oacmxl
    {
        if (i_pos_for_check_oacscl != 0)
        {
            if (bytebuff_setPosition(p_st_ora_packet->p_st_packet, i_pos_for_check_oacscl) != FR_SUCC)
                goto error;
            if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oacscl) != FR_SUCC) // oacscl
                goto error;
            if (s_oacscl == 0x81)
            {
                if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_oacmxl) != FR_SUCC) // oacmxl
                    goto error;
                p_st_sess->i_use_oci = FR_YES;
                p_st_sess->i_ptr_len = APM_ORA_PTR_LEN_1;
                ORA_PRINT_FATAL("set p_st_sess->i_use_oci = FR_YES, p_st_sess->i_ptr_len = 1\n");
            }
            else
                goto error;
        }
        else
            goto error;
    }

    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_oacmal) != FR_SUCC) // oacmal
        goto error;

    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_oacfl2) != FR_SUCC) // oacfl2
        goto error;

    if (ora_mar_skipDALC(p_st_sess, p_st_ora_packet) != FR_SUCC) // oactoid
        goto error;

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_oacvsn) != FR_SUCC) // oacvsn
        goto error;

    if (p_st_sess->i_ttc8_stmt_resp_oac_skip1 == FR_YES)
    {
        if ((s_oacdty == ORA_DTY_ANYTYPE || s_oacdty == ORA_DTY_NAMED_TYPE || s_oacdty == ORA_DTY_NAMED_TYPE2) && i_oacvsn != 0)
        {
        }
        else
        {
            /**
             * ./apm -n -w 60 -d ../oracle/pcap/sqlplus_oci_oracle/10.2.0.4.0_z_gb2312/sqlplus_gb2312_192.168.18.233_10.2.0.4.0_z_2_192.168.18.168_11.2.0.2_a.pcap
             *      p_st_sess->i_use_special_field == FR_YES && p_st_sess->i_send_typerep == FR_NO && s_oacdty != ORA_DTY_ANYTYPE && s_oacdty != ORA_DTY_NAMED_TYPE && s_oacdty != ORA_DTY_NAMED_TYPE2
             */
            ORA_PRINT_DBG("oac skip OCI2\n");
            if (ora_mar_skip(p_st_ora_packet, 2) != FR_SUCC)
                goto error;
            if (p_st_sess->i_ttc8_stmt_resp_oac_skipaftervsn == FR_YES) // p_st_sess->c_ttc_version >= 4 && p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_8
            {
                ORA_PRINT_DBG("oac skip OCI4\n");
                if (ora_mar_skip(p_st_ora_packet, 4) != FR_SUCC)
                    goto error;
            }
        }
    }

    if (ora_mar_unmarshalUB2(p_st_sess, p_st_ora_packet, &i_oaccsi) != FR_SUCC) // oaccsi
        goto error;

    if (ora_mar_unmarshalUB1(p_st_ora_packet, &s_oaccsfrm) != FR_SUCC) // oaccsfrm
        goto error;

    // 不支持c_ttc_version<2的版本
    // 不支持s_tns_version<312的版本(8i)
    // p_st_sess->i_use_special_field == FR_NO || (p_st_sess->i_use_special_field == FR_YES && p_st_sess->s_tns_version >= 312)
    if (ora_mar_unmarshalSB4(p_st_sess, p_st_ora_packet, &i_oacmxlc) != FR_SUCC) // oacmxlc
        goto error;

    if (p_st_sess->i_ttc8_stmt_resp_oac_skip1 == FR_YES)
    {
        if ((s_oacdty == ORA_DTY_ANYTYPE || s_oacdty == ORA_DTY_NAMED_TYPE || s_oacdty == ORA_DTY_NAMED_TYPE2) && i_oacvsn != 0)
        {
        }
        else
        {
            ORA_PRINT_DBG("oac skip OCI1\n");
            if (ora_mar_skip(p_st_ora_packet, 1) != FR_SUCC)
                goto error;
            if (p_st_sess->i_ptr_len == APM_ORA_PTR_LEN_8)
            {
                ORA_PRINT_DBG("oac skip OCI4\n");
                if (ora_mar_skip(p_st_ora_packet, 4) != FR_SUCC)
                    goto error;
            }
        }
    }

    if (s_oacdty == 0)
    {
        ORA_PRINT_EMERG("error oacdty 0\n");
        ORA_FRLOG_ERROR("error oacdty 0");
        goto error;
    }

    st_ora_metadata.s_oacdty = s_oacdty;
    st_ora_metadata.s_oacflg = s_oacflg;
    st_ora_metadata.s_oacpre = s_oacpre;
    st_ora_metadata.s_oacscl = s_oacscl;
    st_ora_metadata.i_oacmxl = i_oacmxl;
    st_ora_metadata.i_oacmal = i_oacmal;
    st_ora_metadata.i_oacfl2 = i_oacfl2;
    st_ora_metadata.i_oacvsn = i_oacvsn;
    st_ora_metadata.i_oaccsi = i_oaccsi;
    st_ora_metadata.s_oaccsfrm = s_oaccsfrm;
    st_ora_metadata.i_oacmxlc = i_oacmxlc;

    if (i_oac_type == APM_ORA_OACTYPE_DEFINE)
    {
        if (ora_stmt_add_define_metadata(p_st_stmt, st_ora_metadata) != FR_SUCC)
        {
            ORA_PRINT_EMERG("add define metadata failed\n");
            ORA_FRLOG_ERROR("add define metadata failed");
            goto error;
        }
    }
    else if (i_oac_type == APM_ORA_OACTYPE_BIND)
    {
        if (ora_stmt_add_bind_metadata(p_st_stmt, st_ora_metadata) != FR_SUCC)
        {
            ORA_PRINT_EMERG("add bind metadata failed\n");
            ORA_FRLOG_ERROR("add bind metadata failed");
            goto error;
        }
    }
    else if (i_oac_type == APM_ORA_OACTYPE_COLUMN)
    {
        if (ora_stmt_add_column_metadata(p_st_stmt, st_ora_metadata) != FR_SUCC)
        {
            ORA_PRINT_EMERG("add column metadata failed\n");
            ORA_FRLOG_ERROR("add column metadata failed");
            goto error;
        }
    }

    /*
    ORA_PRINT_ALERT("oacdty:[%d] oacflg:[%d] oacpre:[%d] oacscl:[%d] oacmxl:[%d] oacmal:[%d] oacfl2:[%d] oacvsn:[%d] oaccsi:[%d] oaccsfrm:[%d] oacmxlc:[%d]\n",
            s_oacdty,
            s_oacflg,
            s_oacpre,
            s_oacscl,
            i_oacmxl,
            i_oacmal,
            i_oacfl2,
            i_oacvsn,
            i_oaccsi,
            s_oaccsfrm,
            i_oacmxlc);
    */

    ORA_PRINT_INFO("leave oac\n");
    return FR_SUCC;
error:
    return FR_FAIL;
}
